package com.yz.fanrenmianshi.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yz.fanrenmianshi.common.ErrorCode;
import com.yz.fanrenmianshi.constant.CommonConstant;
import com.yz.fanrenmianshi.exception.ThrowUtils;
import com.yz.fanrenmianshi.mapper.QuestionCommentMapper;
import com.yz.fanrenmianshi.mapper.QuestionCommentThumbMapper;
import com.yz.fanrenmianshi.model.dto.questioncomment.QuestionCommentQueryRequest;
import com.yz.fanrenmianshi.model.entity.Question;
import com.yz.fanrenmianshi.model.entity.QuestionComment;
import com.yz.fanrenmianshi.model.entity.QuestionCommentThumb;
import com.yz.fanrenmianshi.model.entity.User;
import com.yz.fanrenmianshi.model.vo.QuestionCommentVO;
import com.yz.fanrenmianshi.model.vo.UserVO;
import com.yz.fanrenmianshi.service.CommentThumbRedisService;
import com.yz.fanrenmianshi.service.QuestionCommentService;
import com.yz.fanrenmianshi.service.QuestionService;
import com.yz.fanrenmianshi.service.UserService;
import com.yz.fanrenmianshi.utils.SqlUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 题目评论服务实现
 *
 */
@Service
@Slf4j
public class QuestionCommentServiceImpl extends ServiceImpl<QuestionCommentMapper, QuestionComment> implements QuestionCommentService {

    @Resource
    private UserService userService;

    @Resource
    private QuestionCommentThumbMapper questionCommentThumbMapper;

    @Resource
    private CommentThumbRedisService commentThumbRedisService;

    @Resource
    private QuestionService questionService;

    /**
     * 校验数据
     *
     * @param questionComment
     * @param add      对创建的数据进行校验
     */
    @Override
    public void validQuestionComment(QuestionComment questionComment, boolean add) {
        ThrowUtils.throwIf(questionComment == null, ErrorCode.PARAMS_ERROR);
        // 从对象中取值
        String content = questionComment.getContent();
        Long questionId = questionComment.getQuestionId();
        // 创建数据时，参数不能为空
        if (add) {
            ThrowUtils.throwIf(StringUtils.isBlank(content), ErrorCode.PARAMS_ERROR, "评论内容不能为空");
            ThrowUtils.throwIf(questionId == null || questionId <= 0, ErrorCode.PARAMS_ERROR, "题目ID不能为空");
        }
        // 修改数据时，有参数则校验
        if (StringUtils.isNotBlank(content)) {
            ThrowUtils.throwIf(content.length() > 1000, ErrorCode.PARAMS_ERROR, "评论内容过长");
        }
    }

    /**
     * 获取查询条件
     *
     * @param questionCommentQueryRequest
     * @return
     */
    @Override
    public QueryWrapper<QuestionComment> getQueryWrapper(QuestionCommentQueryRequest questionCommentQueryRequest) {
        QueryWrapper<QuestionComment> queryWrapper = new QueryWrapper<>();
        if (questionCommentQueryRequest == null) {
            return queryWrapper;
        }
        // 从对象中取值
        Long id = questionCommentQueryRequest.getId();
        Long notId = questionCommentQueryRequest.getNotId();
        Long questionId = questionCommentQueryRequest.getQuestionId();
        String content = questionCommentQueryRequest.getContent();
        String searchText = questionCommentQueryRequest.getSearchText();
        String sortField = questionCommentQueryRequest.getSortField();
        String sortOrder = questionCommentQueryRequest.getSortOrder();
        Long userId = questionCommentQueryRequest.getUserId();
        Long parentId = questionCommentQueryRequest.getParentId();
        Long rootId = questionCommentQueryRequest.getRootId();
        Long replyUserId = questionCommentQueryRequest.getReplyUserId();

        // 补充需要的查询条件
        // 从多字段中搜索
        if (StringUtils.isNotBlank(searchText)) {
            // 需要拼接查询条件
            queryWrapper.like("content", searchText);
        }
        // 模糊查询
        queryWrapper.like(StringUtils.isNotBlank(content), "content", content);
        // 精确查询条件
        queryWrapper.eq(ObjectUtils.isNotEmpty(id), "id", id);
        queryWrapper.ne(ObjectUtils.isNotEmpty(notId), "id", notId);
        queryWrapper.eq(ObjectUtils.isNotEmpty(questionId), "questionId", questionId);
        queryWrapper.eq(ObjectUtils.isNotEmpty(userId), "userId", userId);
        queryWrapper.eq(ObjectUtils.isNotEmpty(parentId), "parentId", parentId);
        queryWrapper.eq(ObjectUtils.isNotEmpty(rootId), "rootId", rootId);
        queryWrapper.eq(ObjectUtils.isNotEmpty(replyUserId), "replyUserId", replyUserId);
        // 排序规则
        queryWrapper.orderBy(SqlUtils.validSortField(sortField),
                sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
                sortField);
        return queryWrapper;
    }

    /**
     * 获取题目评论封装
     *
     * @param questionComment
     * @param request
     * @return
     */
    @Override
    public QuestionCommentVO getQuestionCommentVO(QuestionComment questionComment, HttpServletRequest request) {
        // 对象转封装类
        QuestionCommentVO questionCommentVO = QuestionCommentVO.objToVo(questionComment);

        // todo 可以根据需要为封装对象补充值，不需要的内容可以删除
        // region 可选
        // 1. 关联查询用户信息
        Long userId = questionComment.getUserId();
        User user = null;
        if (userId != null && userId > 0) {
            user = userService.getById(userId);
        }
        UserVO userVO = userService.getUserVO(user);
        questionCommentVO.setUser(userVO);

        // 设置回复用户信息
        Long replyUserId = questionComment.getReplyUserId();
        if (replyUserId != null && replyUserId > 0) {
            User replyUser = userService.getById(replyUserId);
            questionCommentVO.setReplyUser(userService.getUserVO(replyUser));
        }

        // 2. 已登录，获取用户点赞、收藏状态
        long questionCommentId = questionComment.getId();
        User loginUser = userService.getLoginUserPermitNull(request);
        if (loginUser != null) {
            // 使用Redis获取点赞状态
            boolean hasLiked = commentThumbRedisService.hasUserLikedComment(questionCommentId, loginUser.getId());
            questionCommentVO.setHasThumb(hasLiked);
        }

        // 使用Redis获取点赞数量
        Long thumbCount = commentThumbRedisService.getCommentLikeCount(questionCommentId);
        questionCommentVO.setThumbNum(thumbCount.intValue());
        // endregion

        return questionCommentVO;
    }

    /**
     * 分页获取题目评论封装
     *
     * @param questionCommentPage
     * @param request
     * @return
     */
    @Override
    public Page<QuestionCommentVO> getQuestionCommentVOPage(Page<QuestionComment> questionCommentPage, HttpServletRequest request) {
        List<QuestionComment> questionCommentList = questionCommentPage.getRecords();
        Page<QuestionCommentVO> questionCommentVOPage = new Page<>(questionCommentPage.getCurrent(), questionCommentPage.getSize(), questionCommentPage.getTotal());
        if (CollUtil.isEmpty(questionCommentList)) {
            return questionCommentVOPage;
        }
        // 对象列表 => 封装对象列表
        List<QuestionCommentVO> questionCommentVOList = questionCommentList.stream().map(questionComment -> {
            return QuestionCommentVO.objToVo(questionComment);
        }).collect(Collectors.toList());

        // 补充封装对象的值
        // 1. 关联查询用户信息
        Set<Long> userIdSet = questionCommentList.stream().map(QuestionComment::getUserId).collect(Collectors.toSet());
        // 添加回复用户ID
        Set<Long> replyUserIdSet = questionCommentList.stream()
                .map(QuestionComment::getReplyUserId)
                .filter(id -> id != null && id > 0)
                .collect(Collectors.toSet());
        userIdSet.addAll(replyUserIdSet);

        Map<Long, List<User>> userIdUserListMap = userService.listByIds(userIdSet).stream()
                .collect(Collectors.groupingBy(User::getId));

        // 2. 已登录，获取用户点赞状态
        Map<Long, Boolean> questionCommentIdHasThumbMap = new HashMap<>();
        User loginUser = userService.getLoginUserPermitNull(request);
        if (loginUser != null) {
            // 使用Redis批量获取点赞状态
            Long[] commentIds = questionCommentList.stream()
                    .map(QuestionComment::getId)
                    .toArray(Long[]::new);
            Boolean[] hasLikedArray = commentThumbRedisService.hasUserLikedComments(commentIds, loginUser.getId());

            for (int i = 0; i < commentIds.length; i++) {
                questionCommentIdHasThumbMap.put(commentIds[i], hasLikedArray[i]);
            }
        }
        // 填充信息
        questionCommentVOList.forEach(questionCommentVO -> {
            // 设置创建用户信息
            Long userId = questionCommentVO.getUserId();
            User user = null;
            if (userIdUserListMap.containsKey(userId)) {
                user = userIdUserListMap.get(userId).get(0);
            }
            questionCommentVO.setUser(userService.getUserVO(user));

            // 设置回复用户信息
            Long replyUserId = questionCommentVO.getReplyUserId();
            if (replyUserId != null && replyUserId > 0) {
                User replyUser = null;
                if (userIdUserListMap.containsKey(replyUserId)) {
                    replyUser = userIdUserListMap.get(replyUserId).get(0);
                }
                questionCommentVO.setReplyUser(userService.getUserVO(replyUser));
            }

            // 设置点赞状态
            questionCommentVO.setHasThumb(questionCommentIdHasThumbMap.getOrDefault(questionCommentVO.getId(), false));

            // 使用Redis获取点赞数量
            Long thumbCount = commentThumbRedisService.getCommentLikeCount(questionCommentVO.getId());
            questionCommentVO.setThumbNum(thumbCount.intValue());

            // 设置题目标题
            Long questionId = questionCommentVO.getQuestionId();
            if (questionId != null && questionId > 0) {
                try {
                    Question question = questionService.getById(questionId);
                    if (question != null) {
                        questionCommentVO.setQuestionTitle(question.getTitle());
                    } else {
                        questionCommentVO.setQuestionTitle("题目#" + questionId);
                    }
                } catch (Exception e) {
                    // 设置一个默认值，避免前端显示为空
                    questionCommentVO.setQuestionTitle("题目#" + questionId);
                }
            }

        });

        questionCommentVOPage.setRecords(questionCommentVOList);
        return questionCommentVOPage;
    }

    @Override
    public void batchDeleteQuestions(List<Long> questionCommentIdList) {
        // 参数校验
        ThrowUtils.throwIf(CollUtil.isEmpty(questionCommentIdList), ErrorCode.PARAMS_ERROR, "评论ID列表不能为空");

        // 批量删除评论
        boolean result = this.removeByIds(questionCommentIdList);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "批量删除评论失败");

        // 删除相关子评论（级联删除）
        QueryWrapper<QuestionComment> childQueryWrapper = new QueryWrapper<>();
        childQueryWrapper.in("parentId", questionCommentIdList);
        List<QuestionComment> childComments = this.list(childQueryWrapper);
        if (CollUtil.isNotEmpty(childComments)) {
            List<Long> childCommentIds = childComments.stream()
                    .map(QuestionComment::getId)
                    .collect(Collectors.toList());
            this.removeByIds(childCommentIds);
        }

        // 删除相关点赞记录
        QueryWrapper<QuestionCommentThumb> thumbQueryWrapper = new QueryWrapper<>();
        thumbQueryWrapper.in("commentId", questionCommentIdList);
        questionCommentThumbMapper.delete(thumbQueryWrapper);

        // 如果有子评论，也要删除子评论的点赞记录
        if (CollUtil.isNotEmpty(childComments)) {
            List<Long> childCommentIds = childComments.stream()
                    .map(QuestionComment::getId)
                    .collect(Collectors.toList());
            QueryWrapper<QuestionCommentThumb> childThumbQueryWrapper = new QueryWrapper<>();
            childThumbQueryWrapper.in("commentId", childCommentIds);
            questionCommentThumbMapper.delete(childThumbQueryWrapper);
        }

        log.info("批量删除评论成功，删除评论数量：{}", questionCommentIdList.size());
    }

    @Override
    public void cascadeDeleteComment(Long commentId) {
        // 参数校验
        ThrowUtils.throwIf(commentId == null || commentId <= 0, ErrorCode.PARAMS_ERROR, "评论ID不能为空");

        // 查询要删除的评论
        QuestionComment comment = this.getById(commentId);
        ThrowUtils.throwIf(comment == null, ErrorCode.NOT_FOUND_ERROR, "评论不存在");

        // 递归查找所有子评论
        List<Long> allCommentIds = new ArrayList<>();
        allCommentIds.add(commentId);
        collectChildCommentIds(commentId, allCommentIds);

        // 批量删除所有评论（包括父评论和子评论）
        boolean result = this.removeByIds(allCommentIds);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "删除评论失败");

        // 删除相关点赞记录
        QueryWrapper<QuestionCommentThumb> thumbQueryWrapper = new QueryWrapper<>();
        thumbQueryWrapper.in("commentId", allCommentIds);
        questionCommentThumbMapper.delete(thumbQueryWrapper);

        log.info("级联删除评论成功，删除评论数量：{}", allCommentIds.size());
    }

    /**
     * 递归收集所有子评论ID
     * @param parentId 父评论ID
     * @param allCommentIds 收集所有评论ID的列表
     */
    private void collectChildCommentIds(Long parentId, List<Long> allCommentIds) {
        // 查询直接子评论
        QueryWrapper<QuestionComment> childQueryWrapper = new QueryWrapper<>();
        childQueryWrapper.eq("parentId", parentId);
        List<QuestionComment> childComments = this.list(childQueryWrapper);

        // 递归处理每个子评论
        for (QuestionComment childComment : childComments) {
            allCommentIds.add(childComment.getId());
            // 递归查找子评论的子评论
            collectChildCommentIds(childComment.getId(), allCommentIds);
        }
    }
}
